package cate.game.activity.specall;

import cate.common.table.activity.specall.row.SpeCallBaseRow;
import cate.common.table.activity.specall.row.SpeCallGroupRow;
import cate.common.table.d.GDObj;
import cate.common.util.GameResult;
import cate.common.util.random.RWList;
import cate.game.activity.base.core.SubActivitySingle;
import cate.game.activity.specall.msg.SpeCallCallDataResp;
import cate.game.activity.specall.msg.SpeCallExeResp;
import cate.game.chat.ChatContentParam;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

@NoteClass("特殊英雄上新")
public class SpeCall  extends SubActivitySingle<SpeCallActivity> {
    @NoteField("状态")
    public SpeCallStatus status;

    public SpeCall(){

    }

    @Override
    public void initialize(SpeCallActivity parent) {
        super.initialize(parent);
        if (status == null) {
            status = new SpeCallStatus();
        }
        status.initialize();
    }

    public void onStart(){
        List<SpeCallBaseRow> rows = role.getGame().table.speCall.base.getRows(parent.configTid());
        if (CollectionUtils.isNotEmpty(rows)) {
            status.updateFreeTimes(rows);
        }
    }

    public void clear() {
        status.clear();
    }

    @JsonIgnore
    private SpeCallBaseRow getBase(int type){
        return role.getGame().table.speCall.base.getRow(parent.configTid(), type);
    }

    public GameResult<Void> call(int type) {
        GameResult<Void> r = new GameResult<>();
        SpeCallBaseRow baseRow = getBase(type);
        if (baseRow == null) {
            return r.fail("错误的召唤类型");
        }
        r = callCheck(baseRow);
        if (!r.ok()) {
            return r;
        }
        List<SpeCallItem> midResult = doCall(baseRow);
        limitRare(baseRow, midResult);
        roleAddResultsSend(baseRow, midResult);
        sendRareNotice(baseRow, midResult);
        noticeUpdate();
        return r;
    }

    /**
     * 召唤条件检测
     *
     * @param baseRow base
     * @return result
     */
    private GameResult<Void> callCheck(SpeCallBaseRow baseRow) {
        GameResult<Void> r = new GameResult<>();
        // 免费次数检测
        if (status.checkFree(baseRow.type)) {
            status.useFreeTimes(baseRow.type);
            return r.success();
        }
        // 召唤券检测
        if (StringUtils.isNotBlank(baseRow.consumeStr)) {
            EcResult<MixResItem> consumeRes = new MixRes(baseRow.consumeStr).consume(role, null);
            if (consumeRes.ok()) {
                return r.success();
            }
        }
        // 元宝检测
        if (baseRow.m1CallTimes > 0) {
            if (!status.checkM1Times(baseRow)) {
                return r.fail("碎钻召唤次数不足");
            }
            EcResult<MixResItem> consumeRes = new MixRes(baseRow.m1ConsumeStr).consume(role, null);
            if (!consumeRes.ok()) {
                role.getGame().notice.tipResItem(role, consumeRes.data);
                return r.fail();
            }
            status.useM1Times(baseRow.callTimes);
            // 元宝抽送经验
            MixRes reward = new MixRes(GDObj.getMixResStr(GDObj.Type.NUM, GDObj.Num.HERO_EXP, baseRow.rewardExp));
            reward.add(role);
            return r.success();
        }
        role.getGame().notice.message(role, 904045, "道具不足");
        return r.fail("道具不足");
    }

    private void limitRare(SpeCallBaseRow baseRow, List<SpeCallItem> midResult) {
        if (baseRow.rareLimit <= 0) {
            return;
        }
        int rareNum = baseRow.rareLimit;
        List<SpeCallItem> removeList = new LinkedList<>();
        for (SpeCallItem item : midResult) {
            SpeCallGroupRow groupRow = role.getGame().table.speCall.group.get(item.id);
            if (groupRow == null) {
                continue;
            }
            if (isUpReward(baseRow, groupRow)) {
                continue;
            }
            if (groupRow.rare) {
                if (rareNum <= 0) {
                    removeList.add(item);
                } else {
                    rareNum--;
                }
            }
        }
        midResult.removeIf(removeList::contains);
        int num = baseRow.callTimes - midResult.size();
        for (int i = 0; i < num; i++) {
            midResult.add(doGeneralCall(baseRow, baseRow.whiteGroup));
        }
    }

    private List<SpeCallItem> doCall(SpeCallBaseRow baseRow){
        List<SpeCallItem> results = new ArrayList<>();
        for (int i = 0; i < baseRow.callTimes; i++) {
            SpeCallGroupRow groupRow = null;
            SpeCallItem item;
            int groupId = status.getUpGroup(baseRow);
            if (groupId > 0) {
                item = new SpeCallItem();
                groupRow = role.getGame().table.speCall.group.findUpRow(baseRow.group, baseRow.upRewardStr);
                if (groupRow != null) {
                    item.id = groupRow.id;
                }
            }else {
                groupId = status.getRareGroup(role.getGame(), baseRow);
                if (groupId > 0) {
                    item = doGeneralCall(baseRow, groupId);
                } else {
                    item = doGeneralCall(baseRow, baseRow.group);
                }
                if (item != null) {
                    groupRow = role.getGame().table.speCall.group.get(item.id);
                }
            }
            if (groupRow != null) {
                status.update(groupRow.rare, isUpReward(baseRow, groupRow));
                results.add(item);
            }
        }
        return results;
    }

    private SpeCallItem doGeneralCall(SpeCallBaseRow baseRow, int groupId) {
        List<SpeCallGroupRow> list = role.getGame().table.speCall.group.getGroupRows(groupId);
        if (list.isEmpty()) {
            return null;
        }
        RWList<SpeCallItem> items = new RWList<>();
        for (SpeCallGroupRow row : list) {
            SpeCallItem item = new SpeCallItem(row);
            if (isUpReward(baseRow, row)) {
                if (status.cheatMustNotCall(baseRow)) {
                    item.weight = 0;
                } else if (groupId == baseRow.group){
                    item.weight += status.callUpTimes * baseRow.addUpWeight;
                }
            }
            items.add(item);
        }
        return items.setup().get();
    }

    @JsonIgnore
    private boolean isUpReward(SpeCallBaseRow baseRow, SpeCallGroupRow groupRow){
        return StringUtils.equals(groupRow.rewardStr, baseRow.upRewardStr);
    }

    private void sendRareNotice(SpeCallBaseRow baseRow, List<SpeCallItem> midResult) {
        if (midResult == null || midResult.isEmpty() || baseRow.lampId == 0 || StringUtils.isBlank(baseRow.actName)) {
            return;
        }
        midResult.forEach(item -> {
            SpeCallGroupRow groupRow = role.getGame().table.speCall.group.get(item.id);
            if (groupRow != null && groupRow.rare) {
                List<ChatContentParam> params = new ArrayList<>();
                params.add(ChatContentParam.c(ChatContentParam.TYPE_STRING, role.getBase().name));
                params.add(ChatContentParam.c(ChatContentParam.TYPE_STRING, baseRow.actName));
                params.add(ChatContentParam.c(ChatContentParam.TYPE_MIX_RES, new MixRes(groupRow.rewardStr)));
                role.getGame().notice.lampOnline(role, baseRow.lampId, params);
            }
        });
    }

    private void roleAddResultsSend(SpeCallBaseRow baseRow, List<SpeCallItem> result) {
        //添加奖励
        List<Integer> resList = new ArrayList<>();
        MixRes reward = new MixRes(baseRow.extraRewardStr);
        if (!result.isEmpty()) {
            for (SpeCallItem it : result) {
                SpeCallGroupRow groupRow = role.getGame().table.speCall.group.get(it.id);
                if (groupRow != null) {
                    reward.addList(new MixRes(groupRow.rewardStr));
                }
                resList.add(it.id);
            }
        }
        logger.info("玩家{}抽到的独立卡池物品为：{}", role.getBase().name, result.stream().map(e -> e.id).collect(Collectors.toList()));
        reward.add(role, true);
        //发消息
        role.sendNow(new SpeCallExeResp(resList,new MixRes(baseRow.extraRewardStr)));
        role.getHistory().action.heroSpeCall(baseRow.callTimes);
    }

    public void noticeUpdate(){
        role.sendNow(new SpeCallCallDataResp(this));
    }

    @Override
    public void onDaySpan(boolean silence) {
        List<SpeCallBaseRow> rows = role.getGame().table.speCall.base.getRows(parent.configTid());
        status.onDaySpan(rows);
    }
}
